﻿Imports System.Linq.Expressions
Imports System.Text.RegularExpressions
Imports Microsoft.JScript

''' <summary>
''' 计算表达式
''' </summary>
Public Class EvalServiceImpl
    Implements IEvalService

    Private r As Regex
    Private JSEngine As Vsa.VsaEngine = Vsa.VsaEngine.CreateEngine ' js引擎

    Private parentPattern As String = "#([a-zA-Z][a-zA-Z0-9]*)"
    Private memberPattern As String = "@([a-zA-Z][a-zA-Z0-9]*)"

    Private regexParent As New Regex(parentPattern)
    Private regexMember As New Regex(memberPattern)

    Public Function ExistsFlag(ByRef str As String) As Boolean Implements IEvalService.ExistsFlag
        Return str Like "*[#]*" OrElse str Like "*[@]*"
    End Function

    Public Function IsExpression(ByRef str As String) As Boolean Implements IEvalService.IsExpression
        Return str Like "*[/+-/*//:/=]*"
    End Function

    Public Function Eval(ByRef jsStr As String) As Object Implements IEvalService.Eval
        Dim result As Object '
        Dim str As String = jsStr
        If str Like "*[/+-/*//:/=]*" Then '是表达式
            Try
                result = Microsoft.JScript.Eval.JScriptEvaluate(str, JSEngine)
            Catch ex As Exception
                Return ex.Message
            End Try
        ElseIf IsNumeric(str) Then
            result = CTypeDynamic(Of Double)(str)
        Else
            result = str
        End If
        Return result
    End Function

    Public Function GetMatch(ByRef str As String, ByRef pattern As String) As Match Implements IEvalService.GetMatch
        r = New Regex(pattern)
        Return r.Match(str)
    End Function

    Public Function GetMatch_ByParent(ByRef str As String) As Match Implements IEvalService.GetMatch_ByParent
        Return GetMatch(str, parentPattern)
    End Function

    Public Function GetMatch_ByMember(ByRef str As String) As Match Implements IEvalService.GetMatch_ByMember
        Return GetMatch(str, memberPattern)
    End Function

    Public Function GetMatchFullValue(ByRef match As Match) As String Implements IEvalService.GetMatchFullValue
        Return match.Groups(0).Value '带符号的值
    End Function

    Public Function GetMatchValue(ByRef match As Match) As String Implements IEvalService.GetMatchValue
        Return match.Groups(1).Value '不带符号的值
    End Function


    ''' <summary>
    ''' 计算表达式
    ''' </summary>
    ''' <param name="expr"> 表达式 </param>
    ''' <param name="self"> 自身对象 </param>
    ''' <param name="parent"> 父对象 </param>
    ''' <returns></returns>
    Public Function AnalyzeExpressions_ByDict(ByRef expr As String, ByRef self As Dictionary(Of String, String), Optional ByRef parent As Dictionary(Of String, String) = Nothing) As Object Implements IEvalService.AnalyzeExpressions_ByDict
        Dim str As String = expr
        Dim match As Match
        Dim errMsg As String = "" ' 错误消息

        Dim count As Integer = 0 ' 避免死循环, 设置计数器
        While ExistsFlag(str) And count < 20
            ' 替换自身属性
            If Not self Is Nothing Then
                match = GetMatch_ByMember(str)
                If GetMatchValue(match) <> "" Then
                    If Not self.ContainsKey(GetMatchValue(match)) Then
                        errMsg = $"自身不存在{GetMatchFullValue(match)}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    str = str.Replace(GetMatchFullValue(match), $"({self(GetMatchValue(match))})") ' 替换
                End If
            End If

            ' 替换包装属性
            If Not parent Is Nothing Then
                match = GetMatch_ByParent(str)
                If GetMatchValue(match) <> "" Then
                    If Not parent.ContainsKey(GetMatchValue(match)) Then
                        errMsg = $"父对象不存在{GetMatchFullValue(match)}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    str = str.Replace(GetMatchFullValue(match), $"({parent(GetMatchValue(match))})") ' 替换
                End If
            End If

                count += 1 '循环计数
        End While

        ' 抛出异常
        If count >= 20 Then
            errMsg = "解析表达式超出限制"
            Throw New NotImplementedException(errMsg)
        End If

        If errMsg <> "" Then Return errMsg
        Return Eval(str)
    End Function

    Public Function AnalyzeExpressions_ByDict(ByRef expr As String, ByRef parent As Dictionary(Of String, Object)) As Object Implements IEvalService.AnalyzeExpressions_ByDict
        Dim str As String = expr
        Dim match As Match
        Dim errMsg As String = "" ' 错误消息

        Dim count As Integer = 0 ' 避免死循环, 设置计数器
        Dim maxCount As Integer = 20 ' 避免死循环, 设置计数器
        While ExistsFlag(str) And count < maxCount
            ' 替换包装属性
            If Not parent Is Nothing Then
                match = regexParent.Match(str) '正则父对象属性

                Dim propertyName As String = GetMatchValue(match) '不带标志的变量名
                Dim flagPropertyName As String = GetMatchFullValue(match) '带有标志的变量名

                If propertyName <> "" Then
                    If Not parent.ContainsKey(propertyName) Then
                        errMsg = $"父对象不存在{flagPropertyName}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    '打断点
                    'If propertyName = "sx" Then
                    '    Debug.Print(parent(propertyName).ToString)
                    'End If
                    str = str.Replace(flagPropertyName, parent(propertyName)) ' 替换
                End If
            End If

            count += 1 '循环计数
        End While

        ' 抛出异常
        If count >= 20 Then
            errMsg = "解析表达式超出限制"
            Throw New NotImplementedException(errMsg)
        End If

        If errMsg <> "" Then Return errMsg
        Return Eval(str)

    End Function



    ''' <summary>
    ''' 计算表达式
    ''' </summary>
    ''' <param name="expr"> 表达式 </param>
    ''' <param name="self"> 自身对象 </param>
    ''' <param name="parent"> 父对象 </param>
    ''' <returns></returns>
    Public Function AnalyzeExpressions_ByEntity(ByRef expr As String, ByRef self As IDataEntity, ByRef Optional parent As IDataEntity = Nothing) As Object Implements IEvalService.AnalyzeExpressions_ByEntity
        Dim str As String = expr
        Dim match As Match
        Dim errMsg As String = "" ' 错误消息

        Dim count As Integer = 0 ' 避免死循环
        While ExistsFlag(str) And count < 20
            ' 替换自身属性
            If Not self Is Nothing Then
                match = GetMatch_ByMember(str)
                If GetMatchValue(match) <> "" Then
                    If self.GetType.GetProperty(GetMatchValue(match)) Is Nothing Then
                        errMsg = $"自身不存在{GetMatchFullValue(match)}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    str = str.Replace(GetMatchFullValue(match), $"({self.GetType.GetProperty(GetMatchValue(match)).GetValue(self)})") ' 替换
                End If
            End If

            ' 替换包装属性
            If Not parent Is Nothing Then
                match = GetMatch_ByParent(str)
                If GetMatchValue(match) <> "" Then
                    If parent.GetType.GetProperty(GetMatchValue(match)) Is Nothing Then
                        errMsg = $"父对象不存在{GetMatchFullValue(match)}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    str = str.Replace(GetMatchFullValue(match), $"({parent.GetType.GetProperty(GetMatchValue(match)).GetValue(parent)})") ' 替换
                End If
            End If

            count += 1 '循环计数
        End While

        ' 抛出异常
        If count >= 20 Then
            Throw New NotImplementedException("解析表达式超出限制")
        End If

        Return Eval(str)
    End Function

    ''' <summary>
    ''' 计算表达式
    ''' </summary>
    ''' <param name="expr"> 表达式 </param>
    ''' <param name="self"> 自身对象 </param>
    ''' <param name="parent"> 父对象 </param>
    ''' <returns></returns>
    Public Function AnalyzeExpressions_ByDatarow(ByRef expr As String, ByRef self As DataRow, ByRef Optional parent As DataRow = Nothing) As Object Implements IEvalService.AnalyzeExpressions_ByDatarow
        Dim str As String = expr
        Dim match As Match
        Dim errMsg As String = "" ' 错误消息

        Dim count As Integer = 0 ' 避免死循环
        While ExistsFlag(str) And count < 20
            ' 替换自身属性
            If Not self Is Nothing Then
                match = GetMatch_ByMember(str)
                If GetMatchValue(match) <> "" Then
                    If self.Table.Columns.Contains(GetMatchValue(match)) Then
                        errMsg = $"自身不存在{GetMatchFullValue(match)}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    str = str.Replace(GetMatchFullValue(match), $"({self.Item(GetMatchValue(match))})") ' 替换
                End If
            End If

            ' 替换包装属性
            If Not parent Is Nothing Then
                match = GetMatch_ByParent(str)
                If GetMatchValue(match) <> "" Then
                    If parent.Table.Columns.Contains(GetMatchValue(match)) Then
                        errMsg = $"父对象不存在{GetMatchFullValue(match)}"
                        Throw New NotImplementedException(errMsg)
                    End If
                    str = str.Replace(GetMatchFullValue(match), $"({parent.Item(GetMatchValue(match))})") ' 替换
                End If
            End If

            count += 1 '循环计数
        End While

        ' 抛出异常
        If count >= 20 Then
            Throw New NotImplementedException("解析表达式超出限制")
        End If

        Return Eval(str)
    End Function



End Class
